package model

import (
	"errors"
	"github.com/go-xorm/xorm"
	"lab-service/helper"
	"time"
)

type User struct {
	Id        int64
	CreatedAt time.Time `xorm:"created"`
	UpdatedAt time.Time `xorm:"updated"`
	Email     string
	Phone     string
	UserName  string
	Password  string `json:"-"`
	Enable    bool   `xorm:"default true"`
}

func (u *User) OneById() error {
	ok, err := orm.ID(u.Id).Get(u)
	if !ok {
		return errors.New(UserNotFound)
	}
	return err
}

func (u *User) OneByPhone() error {
	ok, err := orm.Where("phone = ?", u.Phone).Get(u)
	if !ok {
		return errors.New(UserNotFound)
	}
	return err
}

func (u *User) Page(num, size int32, desc bool, order string) ([]User, error) {
	length := int(size)
	start := (int(num) - 1) * length
	if length == 0 {
		length = 5
	}
	var users []User
	o := orm.Limit(length, start)
	if order == "" {
		order = "id"
	}
	if u.Enable {
		o.Where("enable = ?", true)
	}
	if desc {
		o.Desc(order)
	} else {
		o.Asc(order)
	}
	err := o.Find(&users)
	return users, err
}

func (u *User) Count() (int64, error) {
	o := orm.Where("id > ?", 0)
	if u.Enable {
		o = o.And("enable = ?", true)
	}
	return o.Count(u)
}

func (u *User) Login(pass string) error {
	var o *xorm.Session
	switch {
	case u.Phone != "":
		o = orm.Where("phone = ?", u.Phone)
	case u.UserName != "":
		o = orm.Where("user_name = ?", u.UserName)
	case u.Email != "":
		o = orm.Where("email = ?", u.Email)
	default:
		return errors.New(AccountNameRequired)
	}

	ok, err := o.Get(u)
	if !ok {
		return errors.New(AccountNotFound)
	}

	err = helper.ComparePassword(u.Password, pass)

	return err
}

func (u *User) ChangePass(pass string) error {
	u.Password = helper.EncodePassword(pass)
	if u.Password == "" {
		return errors.New(UserPassHashFailed)
	}

	ok, err := orm.ID(u.Id).Cols("password").Update(u)
	if ok == 0 {
		return errors.New(UserChangePassFailed)
	}
	return err
}

func (u *User) Create(pass string) error {
	u.Password = helper.EncodePassword(pass)
	if u.Password == "" {
		return errors.New(UserPassHashFailed)
	}

	ok, err := orm.Insert(u)
	if ok == 0 {
		return errors.New(UserRegisterFailed)
	}
	return err
}

func (u *User) CheckUnique() error {
	// check if UserName has existed
	ok, _ := orm.Exist(&User{UserName: u.UserName})
	if ok {
		return errors.New(UserNameExist)
	}

	// check if Email has existed
	ok, _ = orm.Exist(&User{Email: u.Email})
	if ok {
		return errors.New(EmailExist)
	}

	// check if Phone has existed
	ok, _ = orm.Exist(&User{Phone: u.Phone})
	if ok {
		return errors.New(PhoneExist)
	}

	// nothing exist
	return nil
}

func (u *User) EnableCheck() error {
	if !u.Enable {
		return errors.New(AccountBanned)
	}
	return nil
}

func (u *User) ExistById() (bool, error) {
	ok, err := orm.ID(u.Id).Exist(u)
	if err != nil {
		return false, err
	} else if !ok {
		return false, errors.New(UserNotFound)
	} else {
		return true, nil
	}
}
